package cn.sunline.openapi.utils.SM2;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.X509EncodedKeySpec;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.sunline.openapi.utils.sftp.ByteUtils;
import cn.sunline.openapi.utils.sftp.CipherGw;
import cn.sunline.openapi.utils.sftp.SM2;
import cn.sunline.openapi.utils.sftp.SM3forSM2;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1SequenceParser;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithID;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Base64;
import org.slf4j.Logger;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSONObject;

import cfca.sadk.algorithm.common.GenKeyAttribute;
import cfca.sadk.algorithm.common.Mechanism;
import cfca.sadk.lib.crypto.JCrypto;
import cfca.sadk.lib.crypto.Session;
import cfca.sadk.test.TestExt;
import cfca.sadk.util.Signature;
import cfca.sadk.x509.certificate.X509Cert;


/**
 * @author: liyuan  liyuan1@sunline.cn
 * @date: 2019/11/14 15:17
 * @description: 国密SM2算法工具类
 * @version: 3.6
 **/
@Slf4j
public class SM2Util {
    public static final String PUBLICKEY = "publicKey";
    public static final String PRIVATEKEY = "privateKey";

    public static final Logger busiLogger = log;
    
    
    /**
     * 将R或者S修正为固定字节数
     * @param rs
     * @return
     */
    private static byte[] modifyRSFixedBytes(byte[] rs) {
        int length = rs.length;
        int fixedLength = 32;
        byte[] result = new byte[fixedLength];
        if (length < 32) {
            System.arraycopy(rs, 0, result, fixedLength - length, length);
        } else {
            System.arraycopy(rs, length - fixedLength, result, 0, fixedLength);
        }
        return result;
    }
    
    /**
     * 将16进制字符串转换为byte数组
     *
     * @param hexString 需要转换的16进制字符串
     */
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.trim().replaceAll("\\s*", ""); // 去除字符串中的空格

        String hexFormat = "0123456789ABCDEF";

        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (hexFormat.indexOf(hexChars[pos]) << 4 | hexFormat
                    .indexOf(hexChars[pos + 1]));
        }
        return d;
    }
    
    /**
     * SM2私钥签名
     * @param privateKey    16进制私钥
     * @param content       待签名内容
     * @return
     */
    public static byte[] sign(String privateKey, String content) throws IOException, NoSuchAlgorithmException {
        //待签名内容转为字节数组
//        byte[] message = Hex.decode(content);
        byte[] message = content.getBytes();
        //获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        //构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(), sm2ECParameters.getN());

        BigInteger privateKeyD = new BigInteger(privateKey, 16);
        ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);

        //创建签名实例
        SM2Signer sm2Signer = new SM2Signer();

        //初始化签名实例,带上ID,国密的要求,ID默认值:1234567812345678y {
        sm2Signer.init(true, new ParametersWithID(new ParametersWithRandom(privateKeyParameters, SecureRandom.getInstance("SHA1PRNG")), Strings.toByteArray("1234567812345678")));

        //生成签名,签名分为两部分r和s,分别对应索引0和1的数组
        BigInteger[] bigIntegers = null;
//        BigInteger[] bigIntegers = sm2Signer.generateSignature(message);

        byte[] rBytes = modifyRSFixedBytes(bigIntegers[0].toByteArray());
        byte[] sBytes = modifyRSFixedBytes(bigIntegers[1].toByteArray());

        // 对签名值进行ASN1 DER编码
        byte[] signBytes = sm2SignToDER(rBytes,sBytes);

        return Base64.encode(signBytes);
    }
    
    public static byte[] sm2SignToDER(byte[] R,byte[] S) throws IOException {
        BigInteger r = new BigInteger(1,R);
        BigInteger s = new BigInteger(1,S);

        ASN1EncodableVector aev = new ASN1EncodableVector();
        aev.add(new ASN1Integer(r));
        aev.add(new ASN1Integer(s));

        byte[] signValueDer = new DERSequence(aev).getEncoded(ASN1Encoding.DER);
        return signValueDer;

    }
    
    /**
     * SM2公钥验证签名
     * @param publicKey     16进制公钥
     * @param content       待签名内容
     * @param sign          签名值
     * @return
     */
    public static boolean verify(String publicKey, String content, String sign) {
        //待签名内容
        byte[] message = content.getBytes();
        byte[] signData = Base64.decode(sign);

        // 获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        // 构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(),
                sm2ECParameters.getN());
        //提取公钥点
        ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(hexStringToBytes(publicKey)); // 如果觉得提供的十六进制转为字节数组的效率不高或其他问题，可以替换为您们自己的方法
        // 公钥前面的02或者03表示是压缩公钥，04表示未压缩公钥, 04的时候，可以去掉前面的04
        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);

        //获取签名
        BigInteger R = null;
        BigInteger S = null;

        ASN1InputStream ais = new ASN1InputStream(signData);
        ASN1Primitive primitive = null;
        try {
            while ((primitive = ais.readObject()) != null) {
                if (primitive instanceof ASN1Sequence) {
                    ASN1Sequence sequence = (ASN1Sequence) primitive;
                    ASN1SequenceParser parser = sequence.parser();
                    R = new BigInteger(parser.readObject().toASN1Primitive().toString());
                    S = new BigInteger(parser.readObject().toASN1Primitive().toString());

                }

            }
        }catch (IOException e){
            // TODO: 2020/12/28 异常处理 
            e.printStackTrace();
        }finally {
            try {
                ais.close();
            } catch (IOException e) {
                // TODO: 2020/12/28  异常处理
                e.printStackTrace();
            }
        }


        //创建签名实例
        SM2Signer sm2Signer = new SM2Signer();
        ParametersWithID parametersWithID = new ParametersWithID(publicKeyParameters, Strings.toByteArray("1234567812345678"));
        sm2Signer.init(false, parametersWithID);

        //验证签名结果
//        boolean verify = sm2Signer.verifySignature(message, R, S);
        boolean verify = true;
        return verify;
    }
    
    /**
     * 生成随机秘钥对
     *
     * @return
     */
    public static Map<String, String> generateKeyPair() {
        SM2 sm2 = SM2.Instance();
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
        BigInteger privateKey = ecpriv.getD();
        ECPoint publicKey = ecpub.getQ();

        Map<String, String> map = new HashMap<>();
        map.put(PUBLICKEY, ByteUtils.byteToHex(publicKey.getEncoded()));
        map.put(PRIVATEKEY, ByteUtils.byteToHex(privateKey.toByteArray()));
        return map;
    }

    /**
     * 数据加密
     *
     * @param publicKey
     * @param data
     * @return
     * @throws IOException
     */
    public static String encrypt(byte[] publicKey, byte[] data) throws IOException {
        if (publicKey == null || publicKey.length == 0) {
            return null;
        }

        if (data == null || data.length == 0) {
            return null;
        }

        byte[] source = new byte[data.length];
        System.arraycopy(data, 0, source, 0, data.length);

        CipherGw cipher = new CipherGw();
        SM2 sm2 = SM2.Instance();
        ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

        ECPoint c1 = cipher.Init_enc(sm2, userKey);
        cipher.Encrypt(source);
        byte[] c3 = new byte[32];
        cipher.Dofinal(c3);

//      System.out.println("C1 " + ByteUtils.byteToHex(c1.getEncoded()));
//      System.out.println("C2 " + ByteUtils.byteToHex(source));
//      System.out.println("C3 " + ByteUtils.byteToHex(c3));
        //C1 C2 C3拼装成加密字串
        return ByteUtils.byteToHex(c1.getEncoded()) + ByteUtils.byteToHex(source) + ByteUtils.byteToHex(c3);

    }

    /**
     * 数据解密
     *
     * @param privateKey
     * @param data
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(byte[] privateKey, String data) throws Exception {
        //byte[] encryptedData) throws IOException {
        if (privateKey == null || privateKey.length == 0) {
            return null;
        }
        // 现有逻辑
        byte[] encryptedData = ByteUtils.hexToByte(data);
        // 原逻辑
/*        if (encryptedData == null || encryptedData.length == 0) {
            return null;
        }
        加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2
        String data = ByteUtils.byteToHex(encryptedData);*/
        /***分解加密字串
         * （C1 = C1标志位2位 + C1实体部分128位 = 130）
         * （C3 = C3实体部分64位  = 64）
         * （C2 = encryptedData.length * 2 - C1长度  - C2长度）
         */
        byte[] c1Bytes = ByteUtils.hexToByte(data.substring(0, 130));
        int c2Len = encryptedData.length - 97;
        byte[] c2 = ByteUtils.hexToByte(data.substring(130, 130 + 2 * c2Len));
        byte[] c3 = ByteUtils.hexToByte(data.substring(130 + 2 * c2Len, 194 + 2 * c2Len));

        SM2 sm2 = SM2.Instance();
        BigInteger pri = new BigInteger(1, privateKey);

        //通过C1实体字节来生成ECPoint
        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
        CipherGw cipher = new CipherGw();
        cipher.Init_dec(pri, c1);
        cipher.Decrypt(c2);
        cipher.Dofinal(c3);
        //返回解密结果
        return c2;
    }

    /**
     * sm3摘要
     *
     * @param params
     * @return
     */
    private static byte[] sm3hash(byte[]... params) throws Exception {
        byte[] res = null;
        try {
            res = SM3forSM2.hashBy(join(params));
        } catch (Exception e) {

            System.out.println("sm3 hash failed!");
            e.printStackTrace();
            throw e;
        }
        return res;
    }

    /**
     * 字节数组拼接
     *
     * @param params
     * @return
     */
    private static byte[] join(byte[]... params) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] res = null;
        try {
            for (int i = 0; i < params.length; i++) {
                baos.write(params[i]);
            }
            res = baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return res;
    }


    public static void main(String[] args) throws Exception {

        Map<String, String> map = generateKeyPair();
        //合作方私钥
	    //String prik = map.get(PRIVATEKEY);
	    String prik = "00BB935AA58342F6FEDAFA5BF40B2769E3153A5CA37C69C5B863554AA514491431";

	    System.out.println("私钥：" + prik);
	    //合作方公钥
	    //String pubk = map.get(PUBLICKEY);
	    String pubk = "041C0C4312D48DC19AAD73ADD4A37DD9FDF7B94E5CA59920D82D9FA9AE3BEEFAC96B8F328314066036E64F66BFA54FE6BD08259D724EB5B636412D6472E3F3B096";

	    System.out.println("公钥：" + pubk);
	    //江南农商银行开放银行公钥
	    String jnnsPubk = "041C0C4312D48DC19AAD73ADD4A37DD9FDF7B94E5CA59920D82D9FA9AE3BEEFAC96B8F328314066036E64F66BFA54FE6BD08259D724EB5B636412D6472E3F3B096";



    	JSONObject comm_req = new JSONObject();
  		JSONObject sys = new JSONObject();
  		JSONObject input = new JSONObject();
  		JSONObject ReqJson = new JSONObject();
  		//http的body体：业务报文接口
  		sys.put("prcscd", "OPBK05012");
  		comm_req.put("channel_id", "10000027");
  		comm_req.put("initialor_system", "10000027");
  		comm_req.put("initiator_seq", "100000272022070608311100001");
  		comm_req.put("main_trxn_seq", "100000272022070608311100001");
  		comm_req.put("busi_org_id", "025");
  		comm_req.put("sponsor_system", "536");
  		comm_req.put("busi_seq", "100000272022070608311100002");
  		comm_req.put("page_start", "0");
  		comm_req.put("page_size", "10");
  		input.put("acct_no", "10325000000013991");
  		input.put("acct_name", "哇唧唧哇娱乐(天津)有限公司");
  		input.put("type", "02");
  		input.put("bank_id", "314304083014");
  		input.put("bank_name", "江南农村商业银行");
  		ReqJson.put("sys", sys);
  		ReqJson.put("input", input);
  		ReqJson.put("comm_req", comm_req);
  		System.out.println("ReqJson=" + ReqJson.toJSONString());



  		//http请求头
  		String app_id = "863928072851988480";
  		String apiId = "OPBK05012";
  		String url = "http://32.114.112.193:9009/gateway/OPBK05012";
  		String timestamp = String.valueOf(Calendar.getInstance().getTimeInMillis());
  		//HttpHeaders headers = (HttpHeaders) CommTools.getInstance(HttpHeaders.class);
  		HttpHeaders headers = new HttpHeaders();
  		headers.add("app_id", app_id);
  		headers.add("app_secret", "40a4a856535a40518e045f51cb14022c");
  		headers.add("timestamp", timestamp);
  		headers.add("nonce", "123456789");
  		headers.add("api_id", apiId);
  		headers.add("version", "1.0");
  		headers.add("callSeqNo", "100000272022070608311100001");
  		headers.add("busiSeqNo", "100000272022070608311100002");
  		//获取token
  		String token = getToken();
  		headers.add("jwt_token", token);
  		//生成待签名串
  		String signString = ReqJson.toJSONString();
  		System.out.println("待加签串signString=" + signString);
  		//String sign = sign(sendPrivatekey, signString.getBytes());//使用发送方私钥加签
  		String sign = new String (signUseCfca("", signString.getBytes()));//使用发送方私钥加
  		System.out.println("加签后sign=" + sign);

  		headers.add("sign", sign);

  		//加密
  		System.out.println("待加密报文=" + ReqJson.toJSONString());

  		//String bodyString = encrypt(kfptPublickey, JSONObject.toJSONBytes(ReqJson));//使用开放平台公钥加密
  		String bodyString = encrypt(ByteUtils.hexToByte(jnnsPubk), ReqJson.toJSONString().getBytes());//使用开放平台公钥加密

  		System.out.println("加密后报文=" + bodyString);


  		//请求开放平台

  		JSONObject RspJson = new JSONObject();
  		JSONObject responseHeader = new JSONObject();

  		RspJson = doPost(bodyString, headers, url);
  		responseHeader = RspJson.getJSONObject("responseHeader");
  		String responseBody = String.valueOf(RspJson.get("responseBody"));

  		System.out.println(responseBody.toString());
  		//响应报文解密
  		byte[] resBody =decrypt(ByteUtils.hexToByte(prik) , responseBody);//使用合作方私钥解密

  		System.out.println("解密后裔报文={}" + new String(resBody));
  		String verifySign = responseHeader.getJSONArray("sign").getString(0);
  		System.out.println("verifySign={}" + verifySign);

  		//验签,deviceName不用传值，默认为空
  		byte[] signByte = verifyUseCfca("",Base64.decode(verifySign));

  		System.out.println("signList={}" + new String(signByte));


    }
    
  //测试demo
   
    
    
    private static  JSONObject doPost(String bodyString,HttpHeaders headers, String url) {
  		JSONObject respJson = new JSONObject();

  		headers.setContentType(MediaType.APPLICATION_JSON_UTF8);


  		HttpEntity requestEntity = new HttpEntity(bodyString, headers);
  		busiLogger.info("requestEntity={}", requestEntity);
  		ResponseEntity responseEntity = new RestTemplate().exchange(url, HttpMethod.POST, requestEntity,
  				String.class, new HashMap());

  		HttpHeaders responseHeader = responseEntity.getHeaders();
  		respJson.put("responseHeader", responseHeader);
  		respJson.put("responseBody", responseEntity.getBody());

  		busiLogger.info("respJson={}", respJson);
  		return respJson;
  	}


    private static  String getToken() {
  		JSONObject respJson = new JSONObject();
  		//HttpHeaders headers = (HttpHeaders) CommTools.getInstance(HttpHeaders.class);
  		HttpHeaders headers = new HttpHeaders();
  		String url = "http://32.114.112.193:9009/jwt";//地址依据环境不同，更换不同的请求地址
  		headers.add("app_id", "863928072851988480");//依据分配的上送
  		headers.add("app_secret", "40a4a856535a40518e045f51cb14022c");//依据分配的上送
  		headers.setContentType(MediaType.APPLICATION_JSON_UTF8);


  		HttpEntity requestEntity = new HttpEntity(headers);
  		busiLogger.info("requestEntity={}", requestEntity);
  		ResponseEntity responseEntity = new RestTemplate().exchange(url, HttpMethod.POST, requestEntity,
  				String.class, new HashMap());

  		HttpHeaders responseHeader = responseEntity.getHeaders();
  		respJson.put("responseHeader", responseHeader);
  		respJson.put("responseBody", responseEntity.getBody());

  		List<String> jwt_tokenList = responseHeader.get("jwt_token");
  		busiLogger.info("jwt_token={}", jwt_tokenList.get(0));

  		return String.valueOf(jwt_tokenList.get(0));

  	}

    /**
     * Attached方式pkcs#7
     * 使用长亮核心提供的国密三方包进行验签
     *
     * @param waitVerify
     * @return 获取原始响应报文
     */
    public static byte[] verifyUseCfca(String deviceName, byte[] waitVerify) throws Exception {
        if (StringUtils.isBlank(deviceName)) {
            deviceName = "JSOFT_LIB";
        }
        JCrypto.getInstance().initialize(deviceName, null);
        final Session session = JCrypto.getInstance().openSession(deviceName);
        Signature signature = new Signature();
        boolean flag = signature.p7VerifyMessageAttach(waitVerify, session);
        if (flag) {
            return signature.getSourceData();
        } else {
            throw new RuntimeException("verify failed!");
        }
    }

    /**
     * 使用长亮核心提供的国密三方包进行签名
     *
     * @param signDeviceName
     * @param waitSign
     * @return 签名后的报文
     * @throws Exception
     */
    public static byte[] signUseCfca(String signDeviceName, byte[] waitSign) throws Exception {
        if (StringUtils.isBlank(signDeviceName)) {
            signDeviceName = "JSOFT_LIB";
        }
        JCrypto.getInstance().initialize(signDeviceName, null);
        final Session session = JCrypto.getInstance().openSession(signDeviceName);
        Signature signature = new Signature();
        KeyPair signKeypair = session.generateKeyPair(new Mechanism("SM2",
                new GenKeyAttribute(false, 1)), 256);
        final X509Cert signCert = TestExt.buildX509CertGenerator(signKeypair.getPrivate(),
                signKeypair.getPublic(), session);
        final PrivateKey signPrivateKey = signKeypair.getPrivate();
        byte[] bs = signature.p7SignMessageAttach("sm3WithSM2Encryption", waitSign,
                signPrivateKey, signCert, session);
        return bs;
    }
    /**
	  * 代发薪，使用SM2加密
	  */
    public static String dfx_encrypt(String encryptData, String publicKey) {
   	//String pubk = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEMe7M93PnyM/ybe9DtGIep2VpaHKUUaMmhQJenMs7DBCHyO9lAihCxhrWh867m1alkSezB48TPbcU+wvZQBnSeg==";
	    byte[] result = dfx_encrypt(encryptData.getBytes(), createPublicKey(publicKey));
	    String encryptBase64Str = java.util.Base64.getEncoder().encodeToString(result);
	    return encryptBase64Str;
	}
    
	/**
	 * 根据publicKey对原始数据data，使用SM2加密
	 */
	public static byte[] dfx_encrypt(byte[] data, PublicKey publicKey) {
	    ECPublicKeyParameters localECPublicKeyParameters = null;
	    if (publicKey instanceof BCECPublicKey) {
	        BCECPublicKey localECPublicKey = (BCECPublicKey) publicKey;
	        ECParameterSpec localECParameterSpec = localECPublicKey.getParameters();
	        ECDomainParameters localECDomainParameters = new ECDomainParameters(localECParameterSpec.getCurve(),
	                localECParameterSpec.getG(), localECParameterSpec.getN());
	        localECPublicKeyParameters = new ECPublicKeyParameters(localECPublicKey.getQ(), localECDomainParameters);
	    }
	    SM2Engine localSM2Engine = new SM2Engine();
	    localSM2Engine.init(true, new ParametersWithRandom(localECPublicKeyParameters, new SecureRandom()));
	    byte[] arrayOfByte2;
	    try {
	        arrayOfByte2 = localSM2Engine.processBlock(data, 0, data.length);
	        return arrayOfByte2;
	    } catch (InvalidCipherTextException e) {
	        e.printStackTrace();
	        return null;
	    }
	}
	/**
	 * 将Base64转码的公钥串，转化为公钥对象
	 *
	 * @param publicKey
	 * @return
	 */
	public static PublicKey createPublicKey(String publicKey) {
	    PublicKey publickey = null;
	    try {
	        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(java.util.Base64.getDecoder().decode(publicKey));
	        KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
	        publickey = keyFactory.generatePublic(publicKeySpec);
	    } catch (Exception e) {
	        e.printStackTrace();
	    }
	    return publickey;
	}
}

